package base;

import structure.interfaces.INode;
import utils.Utils;
import algorithms.CONST;

/**
 * The Chromosome class represent chromosome in the GP algorithm
 *
 */
public class Chromosome {

	// root of the chromosome tree
	private INode _root;
	// fitness
	private double _fitness;

	public double get_fitness() {
		return _fitness;
	}

	public INode get_root() {
		return _root;
	}

	public void set_fitness(double _fitness) {
		this._fitness = _fitness;
	}

	/**
	 * constructor
	 * @param _root - the root of the tree (the chromosome)
	 * @param _fitness
	 */
	public Chromosome(INode _root, double _fitness) {
		this._root = _root;
		this._fitness = _fitness;
	}
	
	public Chromosome() {
		Init();
	}

	/**
	 * generate random chromosome
	 */
	public void Init() {
		Init(CONST.MAX_DEEP_CHROMOSOME-1);	
	}
	
	/**
	 * generate random chromosome with the specified max deep 
	 * @param maxDeep
	 */
	public void Init(int maxDeep) {
		_root = Utils.getRandomOperator();
		_root.generateSubTree(maxDeep);	
	}


	/**
	 * get x and calculate f(x)
	 * @return f(x)
	 */
	public double GetValue(double x) {
		return _root.getValue(x);
	}

	/**
	 * @return max height of the tree
	 */
	public int GetDeep() {
		return _root.getDeep();
	}

	@Override
	public String toString() {
		return _root.getDescription();
	}

	/**
	 * clone the chromosome
	 */
	public Chromosome clone() {
		return new Chromosome(_root.clone(), _fitness);
	}

	/**
	 * clone the chromosome while replacing the specified crossnode with the specified subtree
	 * 
	 * @param crossNode - the cross node in the current tree
	 * @param newSubTree - the new sub tree  
	 * @return cloned chromosome composed from the original and the newSubTree (which replace the crossNode subtree)
	 */
	public Chromosome clone(INode crossNode, INode newSubTree) {
		return new Chromosome(_root.clone(crossNode, newSubTree), _fitness);		
	}
	
	/**
	 * @return random node in the tree (not including the root)
	 */
	 public INode getRandomNode() {
		 return _root.getRandomNode();
	 }


}
